﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

public class MapData
{
    #region 单例

    private MapData()
    {

    }

    private static MapData _instance;

    public static MapData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new MapData();
            }
            return _instance;
        }
    }

    #endregion

    private int[] _dirOddX = new[] {0, 1, 1, 1, 0, -1};
    private int[] _dirEvenX = new[] {-1, 0, 1, 0, -1, -1};
    private int[] _dirY = new[] {-1, -1, 0, 1, 1, 0};

    /// <summary>
    /// 实际的Map数据
    /// </summary>
    public GridData[,] Map = new GridData[Const.MapHeight, Const.MapWidth];


    public List<GridData> Targets = new List<GridData>();

    public int TargetsSuccessNum
    {
        get
        {
            var targetTree = Targets.FindAll(data => data.TreePart != null);
            return targetTree.Count;
        }
    }
    /// <summary>
    /// 生成地图
    /// </summary>
    /// <returns></returns>
    public void Init()
    {
        GenBaseMap();
        GenDirt();
        GenTarget();

    }
    
    public void Reset()
    {
        Map = new GridData[Const.MapHeight, Const.MapWidth];
        Targets = new List<GridData>();
    }

    public List<GridData> GetUseableGrid(GridData data)
    {
        int[] xOffset = data.PosY%2 == 0 ? _dirEvenX : _dirOddX;
        List<GridData> result = new List<GridData>();
        for (int j = 0; j < 6; j++)
        {
            int newX = data.PosX + xOffset[j];
            int newY = data.PosY + _dirY[j];
            if (PosUseable(newX, newY))
            {
                result.Add(Map[newY, newX]);
                
            }
        }
        return result;
    }

    private void GenBaseMap()
    {
        for (int i = 0; i < Const.MapHeight; i++)
        {
            for (int j = 0; j < Const.MapWidth; j++)
            {
                // 跳过奇数行末尾的生成
                if (i % 2 == 1 && j == Const.MapWidth - 1)
                {
                    Map[i, j] = null;
                    continue;
                }
                Map[i, j] = new GridData()
                {
                    PosX = j,
                    PosY = i,
                    Type = i >= Const.DirtStar ? GridType.DirtLowest : GridType.Air,
                    IsTarget = false
                };
            }
        }
    }
    private void GenDirt()
    {
        GenBetterDirtArea(GridType.DirtBest, Const.GenBestDirtNum);
        GenBetterDirtArea(GridType.DirtMiddle, Const.GenMidDirtNum);
    }

    private void GenBetterDirtArea(GridType type, int genTotal)
    {
        GridType arroundType = type - 1;
        for (int i = 0; i < genTotal; i++)
        {
            int genY = Random.Range(Const.DirtStar, Const.MapHeight);
            int genX = GenX(0, Const.MapWidth, genY);
            var genOrgin = Map[genY, genX];
            genOrgin.Type = type;
            var grids =  GetUseableGrid(genOrgin);
            for (int j = 0; j < grids.Count; j++)
            {
                if (PosIsDirt(grids[j].PosX, grids[j].PosY))
                {
                    if (Random.Range(0, 2) > 0)
                    {
                        grids[j].Type = arroundType;
                    }
                }
            }
        }
    }

    private void GenTarget()
    {
        for (int i = 0; i < Const.TargetNum; i++)
        {
            int genY = 0;
            int genX = 0;
            do
            {
                genY = Random.Range(1, Const.DirtStar - 2);
                genX = GenX(0, Const.MapWidth, genY);
            } while (Map[genY, genX].IsTarget);
            Map[genY, genX].IsTarget = true;
            Targets.Add(Map[genY, genX]);
        }
    }

    private int GenX(int minX,int maxX, int posY)
    {
        if (posY%2 == 1 && maxX == Const.MapWidth)
        {
            return Random.Range(minX, Const.MapWidth - 1);
        }
        else
        {
            return Random.Range(minX, Const.MapWidth);
        }
    }
    private bool PosUseable(int x, int y)
    {
        bool xUseable = x >= 0 && ((y%2 == 1) ? x < Const.MapWidth - 1:x<Const.MapWidth);
        bool yUseable = y >= 0 && y < Const.MapHeight;
        return xUseable && yUseable;
    }

    private bool PosIsDirt(int x, int y)
    {
        if (PosUseable(x, y))
        {
            return y >= Const.DirtStar;
        }
        else
        {
            return false;
        }
    }
    
}
